/******************************************************
Cours: LOG121
Session: A2012
Groupe: 01
Projet: Laboratoire #1
Étudiant(e)s: Guillaume Boulay
              Pierre-Olivier Dubé
              Sébastien Gergel
Professeur et chargé de labo : Patrice Boucher
Nom du fichier: ServerConnection.java
Date crée: 2012-10-16
Date dern. modif. 2012-10-16
*******************************************************
Historique des modifications
*******************************************************
2012-10-16 Version initiale (Guillaume Boulay)
*******************************************************/
package server;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;

/**
 * Permet de gérer la connexion au serveur.
 * <br \>
 * Cette classe implémente le pattern singleton. Pour avoir accès à l'instance
 * de la classe, faire `ServerConnection c = ServerConnection.getInstance();`.
 * <br \>
 * Lorsque la classe est utilisé à plus d'un endroit, vérifier si elle n'est
 * pas déjà connecté avec `c.isConnected()`.
 * 
 * @author Guillaume Boulay
 */
public class ServerConnection
{
    private static ServerConnection instance = null;
    private static InetAddress address = null;
    private static int port = 10000;
    private PrintWriter out = null;
    private BufferedReader in = null;
    private Socket socket = null;
    private boolean connected = false;

    /**
     * Ceci est une méthode privée pour implémenter le pattern singleton.
     * Pour accèder à la classe, voir {@link ServerConnection}.
     * @throws UnknownHostException si le host est inconnu.
     */
    private ServerConnection() throws UnknownHostException {    
    	ServerConnection.address = InetAddress.getByName(null);
    }

    /**
     * Point d'entrée de la classe.
     * 
     * @return l'instance de la classe.
     * @throws UnknownHostException si le host est inconnu.
     */
    public static ServerConnection getInstance() throws UnknownHostException
    {
    	if (ServerConnection.instance == null) {
    		ServerConnection.instance = new ServerConnection();
    	}
        return ServerConnection.instance;
    }

    /**
     * Se connecte au serveur.
     * 
     * Si on est déjà connecté, rien ne se passe. S.V.P. vérifier si vous
     * êtes déjà connecté en regardant {@link ServerConnection ici}.
     * 
     * @throws UnknownHostException si l'addresse enregistrer dans la classe
     * n'est pas bonne ou n'existe pas.
     * @throws IOException si il y a une quelconque erreur qui survient.
     */
    public void connect() throws UnknownHostException, IOException
    {
        if (!this.connected) {
            this.socket = new Socket(ServerConnection.address, 
                    ServerConnection.port);

            this.out = new PrintWriter(this.socket.getOutputStream(), true);
            this.in = new BufferedReader(new InputStreamReader(
                    this.socket.getInputStream()));

            this.connected = true;
        }
    }

    /**
     * Retourne une ligne de texte `not null` provenant du serveur.
     * 
     * Execute un `GET` sur le serveur. Ne retourne que la ligne contenant
     * une forme.
     * @return la ligne de texte provenant du serveur.
     * @throws IOException si une quelconque erreur survient ou si on n'est
     * pas connecté.
     */
    public String getLine() throws IOException
    {
        String line = null;

        if (this.connected) {
            // Obtenir la ligne `commande>`
            this.in.readLine();

            this.out.println("GET");
            line = this.in.readLine();
        }

        if (line == null)
            throw new IOException();

        return line;
    }

    /**
     * Ferme la connexion au serveur.
     * 
     * Rien ne se passe si la classe n'est pas connecté au serveur.
     * @throws IOException si jamais une erreur quelconque survient.
     */
    public void close() throws IOException
    {
        if (this.connected) {
            this.out.println("END");

            this.out.close();
            this.in.close();
            this.socket.close();

            this.connected = false;
        }
    }

    /**
     * Retourne un boolean indiquant si la classe est connecté au serveur.
     * 
     * @return un boolean indiquant l'état de la connexion au serveur.
     */
    public boolean isConnected()
    {
        return this.connected;
    }

    /**
     * L'adresse du serveur.
     * 
     * @return l'adresse du serveur.
     */
    public static String getAddress()
    {
        return ServerConnection.address.toString();
    }

    /**
     * Change l'adresse du serveur.
     *  
     * @param address l'adresse du serveur
     * @throws UnknownHostException si le host est inconnu.
     */
    public static void setAddress(String address) throws UnknownHostException
    {
        ServerConnection.address = InetAddress.getByName(address);
    }

    /**
     * Retourne le port auquel le serveur écoute.
     * 
     * @return le port du serveur.
     */
    public static int getPort()
    {
        return ServerConnection.port;
    }

    /**
     * Change le port que la classe utilise pour se connecter au serveur.
     *
     * @param port auquel le serveur se connecte.
     */
    public static void setPort(int port)
    {
        ServerConnection.port = port;
    }
}
